package com.leoandroid.tool.toolsbox.camera

import android.Manifest
import android.annotation.SuppressLint
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.net.Uri
import android.os.Bundle
import android.os.Environment
import android.text.TextUtils
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.blankj.utilcode.util.SPUtils
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.leoandroid.tool.toolsbox.bean.DiscernInfoBean
import com.leoandroid.tool.toolsbox.bean.DiscernTokenBean
import com.leoandroid.tool.toolsbox.bean.WordInfoBean
import com.leoandroid.tool.toolsbox.camera.utils.*
import com.superteam.tool.toolsbox.camera.utils.*
import com.leoandroid.tool.toolsbox.camera.view.CameraXPreviewViewTouchListener
import com.leoandroid.tool.toolsbox.camera.view.FocusImageView
import com.leoandroid.tool.toolsbox.dialog.LoadingDialog
import com.leoandroid.tool.toolsbox.dialog.RecognizeTipsDialog
import com.leoandroid.tool.toolsbox.largeread.utils.ToolUtils
import com.leoandroid.tool.toolsbox.net.NetRequest
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import org.json.JSONObject
import java.io.File
import java.net.URLEncoder
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import com.leoandroid.tool.toolsbox.largeread.R
import com.leoandroid.tool.toolsbox.net.NetCallBack2

/**
 *
 * setLinearZoom: 通过从0f到1.0f的线性变焦值设置当前变焦。LinearZoom 0f表示最小变焦，而LinearZoom 1.0f表示最大变焦。
 * 线性缩放的优点是，它确保视场(FOV)随线性缩放值线性变化，用于滑块UI元素(而setZoomRatio适用于捏缩放手势)
 *
 * @author zhangdecheng
 */
class RecognizeCameraActivity : AppCompatActivity() {
    private var imageCapture: ImageCapture? = null
    private var mCameraControl: CameraControl? = null
    private var mCameraInfo: CameraInfo? = null
    private var focusView: FocusImageView? = null
    private var loadingDialog: LoadingDialog? = null
    private var isInfer = false
    private var imageRotationDegrees: Int = 0
    private var flashMode: Int = ImageCapture.FLASH_MODE_OFF
    private var viewFinder: PreviewView? = null
    private var discernTokenBean: DiscernTokenBean? = null

    // 使用后摄像头
    private var cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

    private lateinit var cameraExecutor: ExecutorService
    private lateinit var bitmapBuffer: Bitmap
    private lateinit var converter: YuvToRgbConverter
    private val ishasCameraPermiss = "ISHASCAMERAPERMISS"
    private var recognizeType = 1

    companion object {
        const val LIGHT_INIT = 0.5f
        private const val REQUEST_CODE_PERMISSIONS = 10
        private val REQUIRED_PERMISSIONS =
                arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)
        private const val TAG = "TAG_RecognizeActivity"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_recognize_camera)

        if (ToolUtils.getHeightStatusBar(this) > 0) {
            findViewById<View>(R.id.layout_padding).setPadding(0, ToolUtils.getHeightStatusBar(this), 0, 0)
        }
        ToolUtils.setStatusBarHomeTransparent(this)

        viewFinder = findViewById(R.id.viewFinder)

        findViewById<View>(R.id.back)?.setOnClickListener {
            finish()
        }

        recognizeType = intent.getIntExtra(Constants.RECOGNIZE_TYPE, Constants.RECOGNIZE_TYPE_PLANT)

        val light = LIGHT_INIT
        setWindowBrightness(light)

        // 对焦框控件
        focusView = findViewById(R.id.focus_view)

        val hasGetPermission = SPUtils.getInstance().getBoolean(ishasCameraPermiss)

        // 请求权限
        if (allPermissionsGranted()) {
            startCamera()
        } else {
            if (!hasGetPermission) {
                try {
                    ActivityCompat.requestPermissions(
                        this,
                        REQUIRED_PERMISSIONS,
                        REQUEST_CODE_PERMISSIONS
                    )
                } catch (_: Exception){
                }
            } else {
                Toast.makeText(this, "没有相机授权与本地存储权限授权，无法使用！", Toast.LENGTH_SHORT).show()
                finish()
            }
        }

        // 点击拍照
        findViewById<ImageButton>(R.id.camera_capture_button).setOnClickListener { takePhoto() }

        cameraExecutor = Executors.newSingleThreadExecutor()

        // 把图像数据转换为RGB格式图像
        converter = YuvToRgbConverter(this)

        // 切换摄像头
        findViewById<ImageButton>(R.id.camera_switch_button).setOnClickListener {
            cameraSelector = if (CameraSelector.DEFAULT_FRONT_CAMERA == cameraSelector) {
                CameraSelector.DEFAULT_BACK_CAMERA
            } else {
                CameraSelector.DEFAULT_FRONT_CAMERA
            }
            // 重启相机
            startCamera()
        }

        // 切换闪光灯模式
        findViewById<ImageButton>(R.id.flash_switch_button).setOnClickListener {
            when (flashMode) {
                ImageCapture.FLASH_MODE_OFF -> {
                    flashMode = ImageCapture.FLASH_MODE_ON
                    findViewById<ImageButton>(R.id.flash_switch_button).setImageResource(R.drawable.reco_open_flash)
                }
                ImageCapture.FLASH_MODE_ON -> {
                    flashMode = ImageCapture.FLASH_MODE_AUTO
                    findViewById<ImageButton>(R.id.flash_switch_button).setImageResource(R.drawable.reco_auto_flash)
                }
                ImageCapture.FLASH_MODE_AUTO -> {
                    flashMode = ImageCapture.FLASH_MODE_OFF
                    findViewById<ImageButton>(R.id.flash_switch_button).setImageResource(R.drawable.reco_stop_flash)
                }
            }
            // 重启相机
            startCamera()
        }
        loadingDialog = LoadingDialog(this, R.style.dialog)
        initData()
    }

    private fun initData() {
        getAccessToken()
    }

    private fun getAccessToken() {
        val sb = StringBuilder()
        sb.append(Constants.BAIDU_AI)
        sb.append("oauth/2.0/token?")
        sb.append("grant_type=client_credentials&client_id=")
        sb.append(Constants.CLIENT_ID)
        sb.append("&client_secret=")
        sb.append(Constants.CLIENT_SECRET)
        NetRequest.asyncGet2(sb.toString(), object : NetCallBack2 {
            override fun onFailure(code: Int, e: Throwable?) {
                Log.e(TAG, ">>> get accessToken failed")
            }

            override fun onSuccess(json: String) {
                Log.d(TAG, ">>> get accessToken success")
                discernTokenBean = Gson().fromJson(json, DiscernTokenBean::class.java)
            }

        })
    }

    // 启动相机
    private fun startCamera() {
        val cameraProviderFuture = ProcessCameraProvider.getInstance(this@RecognizeCameraActivity)

        cameraProviderFuture.addListener({
            // 绑定生命周期
            val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()

            // 设置相机支持预览
            val preview = Preview.Builder().build()
            preview.setSurfaceProvider(viewFinder?.surfaceProvider);

            // 设置相机支持拍照
            imageCapture = ImageCapture.Builder()
                    // 设置闪光灯
                    .setFlashMode(flashMode)
                    // 设置照片质量
                    .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
                    .build()

            // 设置相机支持图像分析
            val imageAnalysis = ImageAnalysis.Builder()
                    .setTargetAspectRatio(AspectRatio.RATIO_4_3)
                    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                    .build()

            // 实时获取图像进行分析
            imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(this)) { image ->
                if (isInfer) {
                    // 执行人脸检测
                    infer(image)
                }
            }

            try {
                // 在重新绑定之前取消绑定用例
                cameraProvider.unbindAll()

                // 将用例绑定到摄像机
                val camera: Camera = cameraProvider.bindToLifecycle(
                        this,
                        cameraSelector,
                        preview,
                        imageCapture,
                        imageAnalysis
                )
                // 相机控制，如点击
                mCameraControl = camera.cameraControl
                mCameraInfo = camera.cameraInfo
                initCameraListener()
            } catch (exc: Exception) {
                Log.e(TAG, "Use case binding failed", exc)
            }

        }, ContextCompat.getMainExecutor(this))
    }

    // 人脸检测
    @SuppressLint("UnsafeExperimentalUsageError", "WrongViewCast", "UnsafeOptInUsageError")
    private fun infer(image: ImageProxy) {
        if (!::bitmapBuffer.isInitialized) {
            imageRotationDegrees = image.imageInfo.rotationDegrees
            Log.d("测试", "方向：$imageRotationDegrees")
            bitmapBuffer = Bitmap.createBitmap(image.width, image.height, Bitmap.Config.ARGB_8888)
        }

        // 将图像转换为RGB，并将其放在bitmapBuffer
        image.use { converter.yuvToRgb(image.image!!, bitmapBuffer) }

        // 画框
        val boxPre: View = findViewById(R.id.box_prediction)
        (boxPre.layoutParams as ViewGroup.MarginLayoutParams).apply {
            topMargin = 20
            leftMargin = 30
            width = 400
            height = 500
        }
    }

    // 拍照
    private fun takePhoto() {
        // 保证相机可用
        val imageCapture = imageCapture ?: return

        val path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
                .toString() + File.separator + "Camera"
        // 保存路径
        val photoFile = File(path, "" + System.currentTimeMillis() + ".jpg")

        // 创建包含文件和metadata的输出选项对象
        val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()

        // 设置图像捕获监听器，在拍照后触发
        imageCapture.takePicture(
                outputOptions,
                ContextCompat.getMainExecutor(this),
                object : ImageCapture.OnImageSavedCallback {
                    override fun onError(exc: ImageCaptureException) {
                        Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
                    }

                    override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                        val savedUri = Uri.fromFile(photoFile)
                        Log.d(TAG, "拍照成功，保存路径: $savedUri")
                        ImageUtils.insertToDB(this@RecognizeCameraActivity, photoFile.absolutePath)
                        val path = FileUtil.bitmapCompress(photoFile.absolutePath)
                        discernTokenBean?.access_token?.let { startRecognize(it, path) }
                    }
                })
    }

    fun startRecognize(token: String, path: String?) {
        if (TextUtils.isEmpty(token) || TextUtils.isEmpty(path)) {
            Toast.makeText(this, "操作频繁，请稍后再试~", Toast.LENGTH_SHORT).show()
            return
        }
        if (!loadingDialog!!.isShowing) {
            loadingDialog!!.show()
        }
        val bytes: ByteArray = FileUtil.readFileByBytes(path)
        val encodeStr: String = Base64Util.encode(bytes)
        val encode: String = URLEncoder.encode(encodeStr, "UTF-8")
        val create: RequestBody = RequestBody.create("application/x-www-form-urlencoded".toMediaTypeOrNull(), "image=$encode")
        val sb = StringBuilder()
        sb.append(Constants.BAIDU_AI)
        sb.append(RecognizeUtil.getRequestPath(recognizeType))
        sb.append("?access_token=")
        sb.append(token)
        NetRequest.asyncPost(create, sb.toString(), object : NetCallBack2 {
            override fun onFailure(code: Int, e: Throwable?) {
                if (loadingDialog!!.isShowing) {
                    loadingDialog!!.dismiss()
                }
                runOnUiThread {
                    Toast.makeText(this@RecognizeCameraActivity, "识别失败，请稍后再试~", Toast.LENGTH_SHORT).show()
                }
            }

            override fun onSuccess(json: String) {
                Log.d(TAG, ">>> recognize success :: result:: $json")
                if (loadingDialog!!.isShowing) {
                    loadingDialog!!.dismiss()
                }
                if (recognizeType == Constants.RECOGNIZE_TYPE_ACCURATE) {
                    try {
                        val result: WordInfoBean = Gson().fromJson(json, WordInfoBean::class.java)
                        runOnUiThread {
                            val recognizeTipsDialog = RecognizeTipsDialog(this@RecognizeCameraActivity, R.style.dialog)
                            recognizeTipsDialog.setWordResult(result, path)
                            recognizeTipsDialog.show()
                        }
                    } catch (e: Exception) {
                        runOnUiThread {
                            Toast.makeText(this@RecognizeCameraActivity, "识别失败，请稍后再试~", Toast.LENGTH_SHORT).show()
                        }
                    }
                } else {
                    try {
                        val jsonObject = JSONObject(json)
                        val result: ArrayList<DiscernInfoBean> = Gson().fromJson(jsonObject.optString("result"), DiscernInfoData().type)
                        runOnUiThread {
                            val recognizeTipsDialog = RecognizeTipsDialog(this@RecognizeCameraActivity, R.style.dialog)
                            recognizeTipsDialog.setDiscernResult(result, path)
                            recognizeTipsDialog.show()
                        }
                    } catch (e: Exception) {
                        runOnUiThread {
                            Toast.makeText(this@RecognizeCameraActivity, "识别失败，请稍后再试~", Toast.LENGTH_SHORT).show()
                        }
                    }
                }

            }

        })
    }

    class DiscernInfoData internal constructor() : TypeToken<ArrayList<DiscernInfoBean?>?>()

    // 相机点击等相关操作监听
    private fun initCameraListener() {
        val cameraXPreviewViewTouchListener = CameraXPreviewViewTouchListener(this)

        cameraXPreviewViewTouchListener.setCustomTouchListener(object :
                CameraXPreviewViewTouchListener.CustomTouchListener {
            override fun zoom(delta: Float) {
            }

            override fun click(x: Float, y: Float) {
            }

            override fun doubleClick(x: Float, y: Float) {
            }

            override fun longPress(x: Float, y: Float) {
            }
        })
        // 添加监听事件
        viewFinder?.setOnTouchListener(cameraXPreviewViewTouchListener)
    }

    override fun onDestroy() {
        super.onDestroy()
        // 关闭相机
        cameraExecutor.shutdown()
    }

    // 权限申请
    private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
        ContextCompat.checkSelfPermission(baseContext, it) == PackageManager.PERMISSION_GRANTED
    }

    // 权限申请结果
    override fun onRequestPermissionsResult(
            requestCode: Int,
            permissions: Array<String>,
            grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == REQUEST_CODE_PERMISSIONS) {
            SPUtils.getInstance().put(ishasCameraPermiss, true)
            if (allPermissionsGranted()) {
                startCamera()
            } else {
                Toast.makeText(this, "没有相机授权与本地存储权限授权，无法使用！", Toast.LENGTH_SHORT).show()
                finish()
            }
        }
    }

    private fun setWindowBrightness(brightness: Float) {
        val window = window
        val lp = window.attributes
        lp.screenBrightness = brightness
        window.attributes = lp
    }
}